<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <title>Gong — Space.js</title>

    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:wght@300&family=Gothic+A1:wght@400;700">
    <link rel="stylesheet" href="assets/css/style.css">

    <script type="module">
        import { BufferLoader, Interface, WebAudio, clamp, delayedCall, guid, ticker } from '../src/index.js';

        class Instructions extends Interface {
            constructor() {
                super('.instructions');

                this.initHTML();
            }

            initHTML() {
                this.invisible();
                this.css({
                    position: 'absolute',
                    left: '50%',
                    bottom: 55,
                    width: 300,
                    marginLeft: -300 / 2,
                    opacity: 0
                });

                this.container = new Interface('.container');
                this.container.css({
                    position: 'absolute',
                    bottom: 0,
                    width: '100%'
                });
                this.add(this.container);

                this.text = new Interface('.text');
                this.text.css({
                    fontFamily: 'Gothic A1, sans-serif',
                    fontWeight: '700',
                    fontSize: 10,
                    lineHeight: 20,
                    letterSpacing: 0.8,
                    textAlign: 'center',
                    textTransform: 'uppercase',
                    opacity: 0.7
                });
                this.text.text(`${navigator.maxTouchPoints ? 'Tap' : 'Click'} for sound`);
                this.container.add(this.text);
            }

            // Public methods

            toggle = (show, delay = 0) => {
                if (show) {
                    this.visible();
                    this.tween({ opacity: 1 }, 800, 'easeInOutSine', delay);
                    this.text.css({ y: 10 }).tween({ y: 0 }, 1200, 'easeOutCubic', delay);
                } else {
                    this.tween({ opacity: 0 }, 300, 'easeOutSine', () => {
                        this.invisible();
                    });
                }
            };
        }

        class UI extends Interface {
            constructor() {
                super('.ui');

                this.initHTML();
                this.initViews();
            }

            initHTML() {
                this.css({
                    minHeight: '100%',
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    flexWrap: 'wrap',
                    padding: '55px 0 125px',
                    pointerEvents: 'none',
                    webkitUserSelect: 'none',
                    userSelect: 'none'
                });
            }

            initViews() {
                this.instructions = new Instructions();
                this.add(this.instructions);
            }
        }

        class AudioController {
            static init(instructions) {
                this.instructions = instructions;

                this.addListeners();
            }

            static addListeners() {
                document.addEventListener('visibilitychange', this.onVisibility);
                document.addEventListener('pointerdown', this.onPointerDown);

                this.instructions.toggle(true);
            }

            // Event handlers

            static onVisibility = () => {
                if (document.hidden) {
                    WebAudio.mute();
                } else {
                    WebAudio.unmute();
                }
            };

            static onPointerDown = ({ clientX, clientY }) => {
                // this.instructions.toggle(false);

                const normalX = clientX / document.documentElement.clientWidth;
                const normalY = clientY / document.documentElement.clientHeight;
                const pan = clamp(((normalX * 2) - 1) * 0.8, -1, 1);
                const rate = clamp(0.8 + (1 - normalY) * 0.4, 0.8, 1.2);

                const gong = WebAudio.clone('gong', guid());
                gong.gain.set(0.5);
                gong.stereoPan.set(pan);
                gong.playbackRate.set(rate);
                gong.play();

                delayedCall(6000, () => {
                    gong.destroy();
                });
            };
        }

        class App {
            static async init() {
                this.initLoader();
                this.initViews();

                this.addListeners();

                await this.bufferLoader.ready();

                this.initAudio();
            }

            static initLoader() {
                this.bufferLoader = new BufferLoader();
                this.bufferLoader.loadAll(['assets/sounds/gong.mp3']);
            }

            static initViews() {
                this.ui = new UI();
                document.body.appendChild(this.ui.element);
            }

            static initAudio() {
                WebAudio.init({ sampleRate: 48000 });
                WebAudio.load(this.bufferLoader.files);

                AudioController.init(this.ui.instructions);
            }

            static addListeners() {
                ticker.start();
            }
        }

        App.init();
    </script>
</head>
<body>
</body>
</html>
